package insight.miescor.opp.domain;

import insight.miescor.annotations.Code;
import insight.miescor.annotations.Constants;
import insight.miescor.annotations.Notebook;
import insight.miescor.annotations.UDF;
import insight.web.delegates.PrimaveraDelegate;

import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.DateConverter;
import org.sormula.Database;
import org.sormula.SormulaException;
import org.sormula.Table;
import org.sormula.annotation.Column;
import org.sormula.annotation.Transient;

import com.primavera.ServerException;
import com.primavera.integration.client.Session;
import com.primavera.integration.client.bo.BusinessObjectException;
import com.primavera.integration.client.bo.object.Project;
import com.primavera.integration.network.NetworkException;

public class Opportunity {

	// region fields
	private String id;

	@Column(name = "market")
	private int dbMarket;
	@Column(name = "portfolio")
	private int dbPortfolio;
	@Column(name = "projectType")
	private int dbProjectType;

	@Code(name = Constants.ProjectFields.MARKET)
	@Transient
	private CodeValue market;
	@Transient
	@Code(name = Constants.ProjectFields.PORTFOLIO)
	private CodeValue portfolio;

	@Transient
	@Code(name = Constants.ProjectFields.PROJECT_TYPE)
	private CodeValue projectType;

	private String title;

	@UDF(name = Constants.ProjectFields.INITIATOR, dataType = Constants.UDFDataType.TEXT)
	@Column(name = "initiator")
	private String userId;

	private String status;
	private int projectId;

	@Transient
	private List<ContractVal> contractVal;

	@Transient
	private String contractValueNotebookText;

	@Transient
	@UDF(name = Constants.ProjectFields.PACKAGE_NAME, dataType = Constants.UDFDataType.TEXT)
	private String packageName;

	@Transient
	@UDF(name = Constants.ProjectFields.CONTRACT_NUMBER, dataType = Constants.UDFDataType.TEXT)
	private String contractNo;

	@Transient
	@Notebook(topicName = Constants.ProjectFields.PRJ_DESCRIPTION)
	private String description;

	@Transient
	private CodeValue location;

	@Code(name = Constants.ProjectFields.CUSTOMER_NAME)
	@Transient
	private CodeValue customer;

	@Code(name = Constants.ProjectFields.IS_JV)
	@Transient
	private CodeValue isJV;

	@Transient
	@Notebook(topicName = Constants.ProjectFields.JV_DETAILS)
	private String jvDetails;

	@Transient
	@Notebook(topicName = Constants.ProjectFields.REG_REQUIREMENT)
	private String regulatoryRequirement;

	@Transient
	@Notebook(topicName = Constants.ProjectFields.RISK_SYNOPSIS)
	private String riskSynopsis;

	@Transient
	@Notebook(topicName = Constants.ProjectFields.FUNDING_DETAILS)
	private String fundingDetail;

	@Transient
	@Notebook(topicName = Constants.ProjectFields.COMPETITVE_ANALYSIS)
	private String competitiveAnaiysis;

	@Transient
	@UDF(name = Constants.ProjectFields.BID_DATE, dataType = Constants.UDFDataType.FINISH_DATE)
	private Date bidDate;

	@Transient
	@UDF(name = Constants.ProjectFields.AWARD_DATE, dataType = Constants.UDFDataType.FINISH_DATE)
	private Date awardDate;

	@Transient
	@UDF(name = Constants.ProjectFields.PRJ_START_DATE, dataType = Constants.UDFDataType.FINISH_DATE)
	private Date prjStDate;

	@Transient
	@UDF(name = Constants.ProjectFields.PROJECT_DURTION, dataType = Constants.UDFDataType.TEXT)
	private String prjDuration;

	@Transient
	@Notebook(topicName = Constants.ProjectFields.ADD_NOTES_ON_TIMELINE)
	private String timelineNotes;

	// endregion fields

	public Opportunity() {

	}

	public Opportunity(Opportunity opp) {
		try {
			ConvertUtils.register(new DateConverter(null), Date.class);
			BeanUtils.copyProperties(this, opp);
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public Opportunity(Session session, Project project)
			throws BusinessObjectException, ServerException, NetworkException {
		
		this.title = project.getName();
		this.projectId = project.getObjectId().toInteger();
		this.location = new CodeValue(
				project.getLocationObjectId().toInteger(),
				project.getLocationName());
		this.id=project.getId();
		PrimaveraDelegate.getDataFromP6(session, project, this);
		String contractValue = PrimaveraDelegate.getProjectNotebookContent(
				session, project,
				Constants.ProjectFields.NOTEBOOK_CONTRACT_VALUE);
		if (contractValue != null && !contractValue.equals("")) {
			List<ContractVal> lstContractValue = new ArrayList<ContractVal>();
			for (String costData : contractValue.split("</br>")) {
				String costValue[] = costData.split(" ");
				lstContractValue
						.add(new ContractVal(costValue[0], costValue[1]));
			}
		}
	}

	
	public void loadP6Data(Session session, Project project) throws BusinessObjectException {
		this.title = project.getName();
		this.projectId = project.getObjectId().toInteger();
		this.location = new CodeValue(
				project.getLocationObjectId().toInteger(),
				project.getLocationName());
		this.id=project.getId();
		PrimaveraDelegate.getDataFromP6(session, project, this);
		String contractValue = PrimaveraDelegate.getProjectNotebookContent(
				session, project,
				Constants.ProjectFields.NOTEBOOK_CONTRACT_VALUE);
		if (contractValue != null && !contractValue.equals("")) {
			List<ContractVal> lstContractValue = new ArrayList<ContractVal>();
			for (String costData : contractValue.split("</br>")) {
				String costValue[] = costData.split(" ");
				lstContractValue
						.add(new ContractVal(costValue[0], costValue[1]));
			}
		}
	}

	public String generateId(Database database, Session session)
			throws SormulaException, BusinessObjectException, ServerException,
			NetworkException {
		SimpleDateFormat sdf = new SimpleDateFormat("yy");
		String prefix = PrimaveraDelegate.getCodeValue(session,
				portfolio.getId())
				+ "O" + sdf.format(new Date());
		System.out.println("Prefix : " + prefix);
		NumberGenerator numGen = NumberGenerator.loadNextNum(database, prefix);
		String runNum = "0000" + numGen.getSeriesCurrentNum();
		System.out.println("running number : " + runNum);

		setId(prefix + "-" + runNum.substring(runNum.length() - 4));
		System.out.println("ID  " + getId());
		return getId();
	}

	public static List<Opportunity> loadAll(Database database) throws Exception {
		Table<Opportunity> oppTable = database.getTable(Opportunity.class);
		return oppTable.selectAll();
	}

	public void save(Database database, Session session, boolean doSubmit,
			String userName) throws Exception {
		try {
			PrimaveraDelegate.saveOpportunity(session, this, userName);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (this.getProjectId() == 0) {
			throw new Exception(
					"Project ID: Unique constraint (Project ID) violated. The value "
							+ this.getId()
							+ " of the field Project ID already exists.");

		}
		Table<Opportunity> oppTable = database.getTable(Opportunity.class);
		this.setStatus("Pending");
		oppTable.insert(this);

		Assignment assObj = new Assignment("initiator", this.getUserId(),
				"Single", 1, 1, this, database);
		assObj.setStatus("Claimed");
		assObj.setStartDate(new Date());
		assObj.insertAssignment(database);

		if (doSubmit) {
			initAssignment(database, assObj);
		}
	}

	public static void initAssignment(Database database, Assignment assObj)
			throws SormulaException, CloneNotSupportedException {
		Table<Assignment> assignmentTable = database.getTable(Assignment.class);
		assObj.setStatus("Complete");
		assObj.setEndDate(new Date());
		assObj.setOutcome("Initiate");
		assignmentTable.update(assObj);

		initiateOpportunity(assObj, assignmentTable, database);
	}

	public static void initiateOpportunity(Assignment assObj, Table<Assignment> assignmentTable, Database database) throws SormulaException, CloneNotSupportedException {
		int nextStep = assObj.getStepId()+1; 
		Assignment assObj1 = (Assignment) assObj.clone();
		//assObj1.setId(Assignment.generateId(database));
		assObj1.setStepId(nextStep);
		assObj1.setEndDate(null);
		assObj1.setStartDate(new Date());
		assObj1.setStatus("Pending");
		assObj1.setUserId("");
		assObj1.setOutcome(null);
		List<WorkflowRole> roles=WorkflowRole.getRolesByStep(database, nextStep);
		if(roles != null){
			for(WorkflowRole role : roles){
				assObj1.setRole(role.getRole());
				assObj1.setId(Assignment.generateId(database));
				System.out.println(role.getRole() + "  " + assObj.getId());
				assignmentTable.insert(assObj1);
			}
		}
		assObj.getOpportunity().setStatus(Workflow.getStageName(database, nextStep));
		Table<Opportunity> oppTable = database.getTable(Opportunity.class);
		oppTable.update(assObj.getOpportunity());
	}
	
	
	public void update(Database database) throws SormulaException {
		Table<Opportunity> oppTable = database.getTable(Opportunity.class);
		oppTable.update(this);
	}

	public static void updateOpp(Database database, Opportunity opp)
			throws SormulaException {
		Table<Opportunity> oppTable = database.getTable(Opportunity.class);
		oppTable.update(opp);
	}

	public static Opportunity getOpportunityById(Database database,
			String itemId) throws SormulaException {
		Table<Opportunity> oppTable = database.getTable(Opportunity.class);
		return oppTable.select(itemId);
	}

	// region Getters & Setters
	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getPackageName() {
		return packageName;
	}

	public void setPackageName(String packageName) {
		this.packageName = packageName;
	}

	public String getContractNo() {
		return contractNo;
	}

	public void setContractNo(String contractNo) {
		this.contractNo = contractNo;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public CodeValue getLocation() {
		return location;
	}

	public void setLocation(CodeValue location) {
		this.location = location;
	}

	public CodeValue getCustomer() {
		return customer;
	}

	public void setCustomer(CodeValue customer) {
		this.customer = customer;
	}

	public CodeValue getIsJV() {
		return isJV;
	}

	public void setIsJV(CodeValue isJV) {
		this.isJV = isJV;
	}

	public String getJvDetails() {
		return jvDetails;
	}

	public void setJvDetails(String jvDetails) {
		this.jvDetails = jvDetails;
	}

	public String getRegulatoryRequirement() {
		return regulatoryRequirement;
	}

	public void setRegulatoryRequirement(String regulatoryRequirement) {
		this.regulatoryRequirement = regulatoryRequirement;
	}

	public String getRiskSynopsis() {
		return riskSynopsis;
	}

	public void setRiskSynopsis(String riskSynopsis) {
		this.riskSynopsis = riskSynopsis;
	}

	public String getFundingDetail() {
		return fundingDetail;
	}

	public void setFundingDetail(String fundingDetail) {
		this.fundingDetail = fundingDetail;
	}

	public String getCompetitiveAnaiysis() {
		return competitiveAnaiysis;
	}

	public void setCompetitiveAnaiysis(String competitiveAnaiysis) {
		this.competitiveAnaiysis = competitiveAnaiysis;
	}

	public Date getBidDate() {
		return bidDate;
	}

	public void setBidDate(Date bidDate) {
		this.bidDate = bidDate;
	}

	public Date getAwardDate() {
		return awardDate;
	}

	public void setAwardDate(Date awardDate) {
		this.awardDate = awardDate;
	}

	public Date getPrjStDate() {
		return prjStDate;
	}

	public void setPrjStDate(Date prjStDate) {
		this.prjStDate = prjStDate;
	}

	public String getPrjDuration() {
		return prjDuration;
	}

	public void setPrjDuration(String prjDuration) {
		this.prjDuration = prjDuration;
	}

	public String getTimelineNotes() {
		return timelineNotes;
	}

	public void setTimelineNotes(String timelineNotes) {
		this.timelineNotes = timelineNotes;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public List<ContractVal> getContractVal() {
		return contractVal;
	}

	public void setContractVal(List<ContractVal> contractVal) {
		this.contractVal = contractVal;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getId() {
		return id;
	}

	public CodeValue getMarket() {
		return market;
	}

	public void setMarket(CodeValue market) {
		this.market = market;
		if (market != null)
			this.dbMarket = market.getId();
	}

	public CodeValue getProjectType() {
		return projectType;
	}

	public void setProjectType(CodeValue projectType) {
		this.projectType = projectType;
		if (projectType != null)
			this.dbProjectType = projectType.getId();
	}

	public static class ContractVal {
		private String value;
		private String currency;

		public ContractVal(String value, String currency) {
			this.value = value;
			this.currency = currency;
		}

		public String getValue() {
			return value;
		}

		public void setValue(String value) {
			this.value = value;
		}

		public String getCurrency() {
			return currency;
		}

		public void setCurrency(String currency) {
			this.currency = currency;
		}
	}

	public CodeValue getPortfolio() {
		return portfolio;
	}

	public void setPortfolio(CodeValue portfolio) {
		this.portfolio = portfolio;
		if (portfolio != null)
			this.dbPortfolio = portfolio.getId();
	}

	public int getProjectId() {
		return projectId;
	}

	public void setProjectId(int projectId) {
		this.projectId = projectId;
	}

	// endregion Getters & Setters

	public int getDbMarket() {
		return dbMarket;
	}

	public void setDbMarket(int dbMarket) {
		this.dbMarket = dbMarket;
	}

	public int getDbPortfolio() {
		return dbPortfolio;
	}

	public void setDbPortfolio(int dbPortfolio) {
		this.dbPortfolio = dbPortfolio;
	}

	public int getDbProjectType() {
		return dbProjectType;
	}

	public void setDbProjectType(int dbProjectType) {
		this.dbProjectType = dbProjectType;
	}

	public String getContractValueNotebookText() {
		return contractValueNotebookText;
	}

	public void setContractValueNotebookText(String contractValueNotebookText) {
		this.contractValueNotebookText = contractValueNotebookText;
	}

}
